/*
 * Copyright (c) 2008-2012, Takashi Ito
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the authors nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef _TANSU_INTERNAL_H_
#define _TANSU_INTERNAL_H_

#include "config.h"

#ifdef WIN32
#define _CRT_SECURE_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#undef SLIST_ENTRY
#endif

#if STDC_HEADERS
#include <stdio.h>
#endif

#if HAVE_STRING_H
#include <string.h>
#endif 
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_STDINT_H
#include <stdint.h>
#endif
#if HAVE_STDARG_H
#include <stdarg.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif

#if HAVE_TIME_H
#include <time.h>
#endif
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_IFADDRS_H
#include <ifaddrs.h>
#endif

#if HAVE_SYS_UN_H
#include <sys/un.h>
#endif
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#if HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#if HAVE_SYS_QUEUE_H
#include <sys/queue.h>
#else
#include "sys/queue.h"
#endif

#if HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#if HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#if HAVE_NET_IF_H
#include <net/if.h>
#ifdef __APPLE__
#include "TargetConditionals.h"
#include <net/if_dl.h>
#ifndef TARGET_OS_IPHONE
#include <net/if_types.h>
#endif
#endif
#endif

#if HAVE_EXPAT_H
#include <expat.h>
#endif
#if HAVE_EVENT_H
#include <event.h>
#endif
#if HAVE_EVHTTP_H
#include <evhttp.h>
#endif
#if HAVE_EVUTIL_H
#include <evutil.h>
#endif

#ifdef HAVE_ASSERT_H
#include <assert.h>
#else
#define assert(expr)
#endif

#include "tdom.h"
#include "tdom_writer.h"

#ifdef WIN32
#define strcasecmp  _stricmp
#define snprintf    _snprintf
#define strdup      _strdup
#endif /* WIN32 */

#ifdef WIN32
#ifndef int16_t
#define int16_t short
#endif
#ifndef uint16_t
#define uint16_t unsigned short
#endif
#ifndef int32_t
#define int32_t int
#endif
#ifndef uint32_t
#define uint32_t unsigned int
#endif
#ifndef socklen_t
#define socklen_t int
#endif
#endif

#ifdef WIN32
#define TANSU_SOCKET_CLOSE(fd)      closesocket(fd)
#define TANSU_GET_SOCKET_ERROR()    WSAGetLastError()
#define TANSU_SOCKET_EINTR          WSAEINTR
#else
#define TANSU_SOCKET_CLOSE(fd)      close(fd)
#define TANSU_GET_SOCKET_ERROR()    (errno)
#define TANSU_SOCKET_EINTR          EINTR
#endif

#define TNUMELEM(array)             (sizeof(array)/sizeof(*array))

#define TLOG_LEVEL_ALL              (~0)
#define TLOG_LEVEL_DEBUG_ONLY       (1<<0)
#define TLOG_LEVEL_INFO_ONLY        (1<<1)
#define TLOG_LEVEL_WARN_ONLY        (1<<2)
#define TLOG_LEVEL_ERROR_ONLY       (1<<3)
#define TLOG_LEVEL_FATAL_ONLY       (1<<4)
                                    
#define TLOG_LEVEL_DEBUG            TLOG_LEVEL_DEBUG_ONLY
#define TLOG_LEVEL_INFO             (TLOG_LEVEL_DEBUG | TLOG_LEVEL_INFO_ONLY)
#define TLOG_LEVEL_WARN             (TLOG_LEVEL_INFO  | TLOG_LEVEL_WARN_ONLY)
#define TLOG_LEVEL_ERROR            (TLOG_LEVEL_WARN  | TLOG_LEVEL_ERROR_ONLY)
#define TLOG_LEVEL_FATAL            (TLOG_LEVEL_ERROR | TLOG_LEVEL_FATAL_ONLY)
                                    
#define TLOG_ALL                    (~0)
#define TLOG_NONE                   (1<<0)
#define TLOG_UTIL                   (1<<1)
#define TLOG_SOCKET                 (1<<2)
#define TLOG_CONSOLE                (1<<3)
#define TLOG_NWIF                   (1<<4)
#define TLOG_SSDP                   (1<<5)
#define TLOG_HTTP                   (1<<6)
#define TLOG_UPNP                   (1<<7)

#define TLOG_DEBUG(category, ...)   TLOG(category, TLOG_LEVEL_DEBUG, "" __VA_ARGS__)
#define TLOG_INFO(category, ...)    TLOG(category, TLOG_LEVEL_INFO,  "" __VA_ARGS__)
#define TLOG_WARN(category, ...)    TLOG(category, TLOG_LEVEL_WARN,  "" __VA_ARGS__)
#define TLOG_ERROR(category, ...)   TLOG(category, TLOG_LEVEL_ERROR, "" __VA_ARGS__)
#define TLOG_FATAL(category, ...)   TLOG(category, TLOG_LEVEL_FATAL, "" __VA_ARGS__)

int tlog_initialize(void *arg);
int tlog_finalize(void *arg);

uint32_t tlog_get_level();
int tlog_set_level(uint32_t level);

uint32_t tlog_get_category();
int tlog_set_category(uint32_t level);

int tlog(uint32_t level, uint32_t category, const char *format, ...);

#ifdef TANSU_DEBUG

#define TLOG(level, category, ...)  tlog(level, category, __VA_ARGS__)
#define TASSERT(expr, ...) do { \
    if (!(expr)) { \
        TLOG_FATAL(TLOG_ALL, "[ASSERT] %s:%d %s\n", __FILE__, __LINE__, #expr); \
        TLOG_FATAL(TLOG_ALL, " " __VA_ARGS__); \
    } \
    assert(expr); \
} while (0);

#else /* TANSU_DEBUG */

#define TLOG(level, category, ...)
#define TASSERT(expr, ...)

#endif /* TANSU_DEBUG */

#define TANSU_MULTICAST_TTL         4

#if HAVE_IFADDRS_H
#else
#define ifaddrs ifaddrs_port
struct ifaddrs_port {
    struct ifaddrs   *ifa_next;
    char             *ifa_name;
    u_int             ifa_flags;
    struct sockaddr  *ifa_addr;
    struct sockaddr  *ifa_netmask;
#if 0
    union {
        struct sockaddr  *ifa_broadaddr;
        struct sockaddr  *ifa_dstaddr;
    } ifa_ifu;
    void             *ifa_data;
#endif
    struct sockaddr sa_addr;
    struct sockaddr sa_netmask;
};
int getifaddrs(struct ifaddrs **ifap);
void freeifaddrs(struct ifaddrs *ifp);
#endif

#if HAVE_STRSEP
#else
#ifdef strsep
#undef strsep
#define strsep _strsep
#endif
char *_strsep(char **stringp, const char *delim);
#endif

#ifdef __GNUC__
#define likely(x)    __builtin_expect((x), 1)
#define unlikely(x)  __builtin_expect((x), 0)
#else
#define likely(x)    (x)
#define unlikely(x)  (x)
#endif

#ifndef STAILQ_CONCAT
#define STAILQ_CONCAT(head1, head2) do { \
    if (!STAILQ_EMPTY((head2))) { \
        *(head1)->stqh_last = (head2)->stqh_first; \
        (head1)->stqh_last = (head2)->stqh_last; \
        STAILQ_INIT((head2)); \
    } \
} while (/*CONSTCOND*/0)
#endif /* STAILQ_CONCAT */

#endif /* _TANSU_INTERNAL_H_ */

